﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.Common;
using FileUtility;
using FileUtility.ExceptionExt;
using FileMonitor.Configuration.Prototype.BizProcess;
namespace FileMonitor.Configuration.Prototype
{
    public class ProcedureProcess:Prototype.BizProcess.BizProcessBase
    {
        private string  _name;
        private string _tagetDatabaseName;
        private string _bizProcedure;
        private string _targetProcedure;
        private int _timeOut;
        private string _sourceDatabaseName;
        private string _sourcesParams;
        private string _targetParams;
     

        Prototype.Provider.IProvider provider;


        public ProcedureProcess(string Name)
            :base(Name)
        {
            this._name = Name;
            provider = Providers.ProviderService.GetProvider();
        }

        public ProcedureProcess(string Name, string SourceDbName, string TargetDatabaseName, string BizProcedure, string TargetProcedure, int TimeOut)
            : base(Name)
        {
            this._name = Name;
            this._tagetDatabaseName = TargetDatabaseName;
            this._bizProcedure = BizProcedure;
            this._targetProcedure = TargetProcedure;
            this._timeOut = TimeOut;
            this._sourceDatabaseName = SourceDbName;
            provider = Providers.ProviderService.GetProvider();
        }

        
        public string TargetDatabaseName
        {
            get { return this._tagetDatabaseName; }
            set { this._tagetDatabaseName = value; }
        }

        public string SourceDatabaseName
        {
            get { return this._sourceDatabaseName; }
            set { this._sourceDatabaseName = value; }
        }

        public string BizProcedure
        {
            get { return this._bizProcedure; }
            set { this._bizProcedure = value; }
        }

        public string TargetProcedure
        {
            get { return this._targetProcedure; }
            set { this._targetProcedure = value; }
        }

        public string TimeOut
        {
            get { return this._timeOut.ToString(); }
            set { Int32.TryParse(value, out this._timeOut); }
        }

        public string SourcesParams
        {
            get { return this._sourcesParams; }
            set
            {
                this._sourcesParams = value.TrimEnd(",".ToCharArray());
            }
        }

        public string TargetParams
        {
            get { return this._targetParams; }
            set
            {
                this._targetParams = value.TrimEnd(",".ToCharArray());
            }
        }

        public override void Excute(ExcutedTask task)
        {
            if (provider != null)
            {
                Dictionary<string, SqlDataBaseExtender> dbs = provider.GetAllDataBase();
                SqlDataBaseExtender sourceDb = null;
                SqlDataBaseExtender targetDb = null;
                if (dbs.ContainsKey(this._sourceDatabaseName))
                {
                    sourceDb = dbs[this._sourceDatabaseName];
                }
                else
                {
                    throw new ConfigurationException("processProviders", this.Name, "SourceDatabaseName", "Can't find the Database!");
                }
                if (dbs.ContainsKey(this._tagetDatabaseName))
                {
                    targetDb = dbs[this._tagetDatabaseName];
                }
                else
                {
                    throw new ConfigurationException("processProviders", this.Name, "TargetDatabaseName", "Can't find the Database!");
                }
                Guid batchID=Guid.Empty;
                if (task.BatchId != null)
                {
                    batchID=new Guid(task.BatchId);
                }
                else
                {
                    throw new ArgumentException("Can't be null", "BatchId");
                }
                if (string.IsNullOrEmpty(this.BizProcedure))
                {
                    try
                    {
                        ExcuteOneWay(targetDb,task);
                        base.OnExcuted(task, BizProcess.ExcutedResult.Successful);
                    }
                    catch (Exception ex)
                    {
                        base.OnExcuted(task, BizProcess.ExcutedResult.Failure);
                    }
                   
                }
                else
                {
                    try
                    {
                        ExcuteTwoWay(sourceDb, targetDb, task);
                        base.OnExcuted(task, BizProcess.ExcutedResult.Successful);
                    }
                    catch (Exception ex)
                    {
                        base.OnExcuted(task, BizProcess.ExcutedResult.Failure);
                    }
                }
              
            }
        }

        public override BizProcess.BizProcessBase Copy()
        {
            ProcedureProcess p = new ProcedureProcess(this.Name, this._sourceDatabaseName, this._tagetDatabaseName, this._bizProcedure, this._targetProcedure, this._timeOut);
            p._sourcesParams = this._sourcesParams;
            p._targetParams = this._targetParams;
            p.NextStatus = this.NextStatus;
            //p.NextBizProcess = this.NextBizProcess;
            return p;
        }

        public void ExcuteOneWay(SqlDataBaseExtender targetDb, ExcutedTask task)
        {
            DbConnection connTarget = targetDb.GetOpenConnetion();
            DbTransaction transTarget = connTarget.BeginTransaction();
            try
            {
                NameValueCollection taskValues = new NameValueCollection();
                taskValues.Add("Owner", task.Owner);
                taskValues.Add("BatchId", task.BatchId);
                taskValues.Add("FileName", task.FileName);
                NameValueCollection paramsS = CombineTaskWithParams(taskValues, SourcesParams);
                 targetDb.ExecuteNonQuery(transTarget, this.TargetProcedure, paramsS,this._timeOut);
                //targetDb.ExecuteDataSet(this.TargetProcedure, paramsS);
                transTarget.Commit();
                connTarget.Close();
            }
            catch (Exception ex)
            {
                if (transTarget != null && connTarget != null)
                {
                  //  transTarget.Rollback();
                    connTarget.Close();
                }
                throw new Exception(ex.Message);
            }
        }

        public void ExcuteTwoWay(SqlDataBaseExtender sourceDb, SqlDataBaseExtender targetDb, ExcutedTask task)
        {

            DbConnection connSource = sourceDb.GetOpenConnetion();
            DbConnection connTarget = targetDb.GetOpenConnetion();
            DbTransaction transSource = connSource.BeginTransaction();
            DbTransaction tranTarget = connTarget.BeginTransaction();
            NameValueCollection taskValues = new NameValueCollection();
            taskValues.Add("Owner", task.Owner);
            taskValues.Add("BatchId", task.BatchId);
            taskValues.Add("FileName", task.FileName);
            NameValueCollection paramsS = CombineTaskWithParams(taskValues, SourcesParams);
            NameValueCollection paramsT = CombineTaskWithParams(taskValues, TargetParams);

            try
            {
                sourceDb.ExecuteNonQuery(transSource, this.BizProcedure, paramsS, this._timeOut);
                transSource.Commit();
                connSource.Close();
            }
            catch (Exception ex)
            {
                if (transSource != null && connSource != null)
                {
                    transSource.Rollback();
                    connSource.Close();
                }
                throw new Exception(ex.Message);
            }

            try
            {
                targetDb.ExecuteNonQuery(tranTarget, this.TargetProcedure, paramsT, this._timeOut);
                tranTarget.Commit();
                connTarget.Close();
            }
            catch (Exception ex)
            {
                if (tranTarget != null && connTarget != null)
                {
                    tranTarget.Rollback();
                    connTarget.Close();
                }

                throw new Exception(ex.Message);
            }
        }

        private NameValueCollection CombineTaskWithParams(NameValueCollection task,string paramsString) 
        {
            NameValueCollection values = new NameValueCollection();
            foreach(string key in task.Keys)
            {
                values.Add(key, task[key]);
            }
            NameValueCollection nv= Utility.ParseNameValueCollection(paramsString);
            if (nv != null)
            {
                foreach (string key in nv.Keys)
                {
                    values[key] = nv[key];
                }
            }
            return values;
        }

        private string ConstructParamsString(DbParameterCollection inputParams, NameValueCollection values, string fixParams)
        {
            string retStr = "";
            foreach (string key in values.Keys)
            {
                string k = "@" + key;
                if (inputParams.Contains(k))
                {
                    string v = values[key];
                    string str = string.Format("{0}='{1}'", k, v);
                    retStr = retStr + str + ",";
                }
            }
            retStr = retStr.TrimEnd(",".ToCharArray());
            if (!string.IsNullOrEmpty(fixParams))
            {
                retStr = retStr + "," + fixParams;
            }
            return retStr;
        }

        private string ParseNameValueCollectionToSqlParams(NameValueCollection values)
        {
            string retStr = "";
            foreach (string key in values.Keys)
            {
                string k = "@" + key;
                string v = values[key];
                string str = string.Format("{0}='{1}'",k,v);
                retStr = retStr + str+",";
            }
            retStr = retStr.TrimEnd(",".ToCharArray());
            return retStr;
            
        }
    }
}
